# subprocess 模块允许我们启动一个新进程，并连接到它们的输入/输出/错误管道，从而获取返回值。
import subprocess
# subprocess.run(args, *, stdin=None, input=None, stdout=None, stderr=None, shell=False, timeout=None, check=False, encoding=None, errors=None)
# 功能：执行args参数所表示的命令，等待命令结束，并返回一个CompletedProcess类型对象。
# args：表示要执行的命令。必须是一个字符串，字符串参数列表。
# stdin、stdout和stderr：子进程的标准输入、输出和错误
# timeout：设置命令超时时间。如果命令执行时间超时，子进程将被杀死，并弹出TimeoutExpired异常。
# check：如果该参数设置为True，并且进程退出状态码不是0，则弹出CalledProcessError异常。
# encoding:如果指定了该参数，则stdin、stdout和stderr可以接收字符串数据，并以该编码方式编码。否则只接收bytes类型的数据。
# shell：如果该参数为True，将通过操作系统的shell执行指定的命令。


def test_run():
    result = subprocess.run('dir', shell=True)
    print(result)
    # subprocess.run('exit 1',shell=True,check=True)
    result = subprocess.run('python --version', stdout=subprocess.PIPE)
    print(result)
    s = subprocess.run("ipconfig", stdout=subprocess.PIPE)
    print(s.stdout.decode("GBK"))
    # run()方法的返回值，表示一个进程结束了。CompletedProcess类有下面这些属性：
    # args 启动进程的参数，通常是个列表或字符串。
    # returncode 进程结束状态返回码。0表示成功状态。
    # stdout 获取子进程的stdout。通常为bytes类型序列，None表示没有捕获值。如果你在调用run()方法时，设置了参数stderr = subprocess.STDOUT，则错误信息会和stdout一起输出，此时stderr的值是None。
    # stderr 获取子进程的错误信息。通常为bytes类型序列，None表示没有捕获值。
    # check_returncode() 用于检查返回码。如果返回状态码不为零，弹出CalledProcessError异常。


def test():
    ret = subprocess.run('dir E:\\', shell=True)

    ret = subprocess.run(['dir', 'E:\\'])
    ret = subprocess.run(['dir', 'E:\\'], shell=True)

    ret = subprocess.run('ipconfig /all')
    ret = subprocess.run('ipconfig /all', shell=True)

    ret = subprocess.run(['ipconfig', '/all'])
    ret = subprocess.run(['ipconfig', '/all'], shell=True)

    # ret = subprocess.call(['ls','-l'])# Linux命令windows无法使用
    # 在windows中，args和shell参数组合比较复杂，根据命令的不同有不同的情况。建议shell设置为True。

# 获得执行结果


def get_result():
    # run()方法返回的是一个CompletedProcess类型对象，不能直接获取我们通常想要的结果。要获取命令执行的结果或者信息，在调用run()方法的时候，请指定stdout = subprocess.PIPE。
    ret = subprocess.run('dir', shell=True)
    print(ret)
    ret = subprocess.run('dir', shell=True, stdout=subprocess.PIPE,)
    print(ret)
    print(ret.stdout)
    print(ret.stdout.decode("GBK"))
# 交互式输入


def test_input():
    fd = open('1.txt')
    ret = subprocess.run('python', stdin=fd,
                         stdout=subprocess.PIPE, shell=True)
    print(ret.stdout)
    fd.close()


def test_Popen():
    # Popen对象的stdin、stdout和stderr是三个文件句柄，可以像文件那样进行读写操作。
    ret = subprocess.Popen('dir', shell=True)
    print(ret)
    s = subprocess.Popen("ipconfig", stdout=subprocess.PIPE, shell=True)
    print(s.stdout.read().decode("GBK"))
    # 通过s.stdin.write()可以输入数据，而s.stdout.read()则能输出数据。
    s = subprocess.Popen('Python', stdout=subprocess.PIPE,
                         stdin=subprocess.PIPE, shell=True)
    s.stdin.write(b"import os\n")
    s.stdin.write(b"print(os.environ)")
    s.stdin.close()
    out = s.stdout.read().decode("GBK")
    s.stdout.close()
    print(out)


# subprocess.run()和subprocess.Popen()的执行结果是写入到缓存的，可以执行结束后打印结果，不会实时在终端输出；而os.system()是实时输出到终端界面的；
if __name__ == '__main__':
    test_run()
    get_result()
    test_input()
    test_Popen()
